package com.xuzhiguang.lightnat.server.wrap.manager;

import cn.hutool.core.util.RandomUtil;
import com.xuzhiguang.lightnat.common.manager.ControlChannelManager;
import com.xuzhiguang.lightnat.common.util.IdUtil;
import com.xuzhiguang.lightnat.server.core.client.*;
import com.xuzhiguang.lightnat.server.core.exception.NatClientNotFoundException;
import com.xuzhiguang.lightnat.server.core.exception.NatProxyNotFoundException;
import com.xuzhiguang.lightnat.server.core.server.proxy.ProxyServer;
import com.xuzhiguang.lightnat.server.wrap.bean.Client;
import com.xuzhiguang.lightnat.server.wrap.bean.Proxy;
import io.netty.channel.Channel;
import org.springframework.beans.BeanUtils;

import java.util.List;
import java.util.stream.Collectors;

public class NatClientManager {

    private final NatClientService natClientService;

    private final ProxyServer proxyServer;

    public NatClientManager(NatClientService natClientService, ProxyServer proxyServer) {
        this.natClientService = natClientService;
        this.proxyServer = proxyServer;
    }

    public List<Client> listAllClient() {
        return this.natClientService.getAllNatClients().stream().map(natClient -> {
            Client client = new Client();
            BeanUtils.copyProperties(natClient, client);
            return client;
        }).collect(Collectors.toList());
    }

    public List<Proxy> listProxyByClientId(long clientId) throws NatClientNotFoundException {
        return this.natClientService.getNatProxies(clientId).stream().map(natProxy -> {
            Proxy proxy = new Proxy();
            BeanUtils.copyProperties(natProxy, proxy);
            return proxy;
        }).collect(Collectors.toList());
    }

    public Client addClient(Client client) {

        client.setId(IdUtil.nextId());
        client.setToken(RandomUtil.randomString(32));
        NatClient natClient = new DefaultNatClient();
        BeanUtils.copyProperties(client, natClient);
        this.natClientService.addNatClient(natClient);

        return client;
    }

    public void modifyClient(Client client) throws NatClientNotFoundException {
        NatClient natClient = new DefaultNatClient();
        BeanUtils.copyProperties(client, natClient);
        this.natClientService.modifyNatClient(client.getId(), natClient);
    }

    public void deleteClient(long clientId) {

        this.natClientService.deleteNatClient(clientId);
        Channel channel = ControlChannelManager.getChannel(clientId);
        if (channel != null) {
            ControlChannelManager.remove(channel);
            channel.close();
        }
    }


    public Proxy addProxy(Proxy proxy) throws NatClientNotFoundException {

        proxy.setId(IdUtil.nextId());
        NatProxy natProxy = new DefaultNatProxy();
        BeanUtils.copyProperties(proxy, natProxy);
        this.natClientService.addNatProxy(natProxy);
        proxyServer.bind(proxy.getId(), proxy.getProxyHost(), proxy.getProxyPort());

        return proxy;
    }

    public void modifyProxy(Proxy proxy) throws NatProxyNotFoundException {

        NatProxy natProxy = new DefaultNatProxy();
        BeanUtils.copyProperties(proxy, natProxy);

        NatProxy oldNatProxy = natClientService.modifyNatProxy(proxy.getId(), natProxy);

        proxyServer.unbind(oldNatProxy.getId());
        proxyServer.bind(oldNatProxy.getId(), natProxy.getProxyHost(), natProxy.getProxyPort());
    }

    public void deleteProxy(long proxyId) {
        this.natClientService.deleteNatProxy(proxyId);
        proxyServer.unbind(proxyId);
    }


}
